package org.future.wsdl.utils;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.wsdl.Binding;
import javax.wsdl.BindingFault;
import javax.wsdl.BindingInput;
import javax.wsdl.BindingOperation;
import javax.wsdl.BindingOutput;
import javax.wsdl.Definition;
import javax.wsdl.Fault;
import javax.wsdl.Input;
import javax.wsdl.Message;
import javax.wsdl.Operation;
import javax.wsdl.Output;
import javax.wsdl.Part;
import javax.wsdl.Port;
import javax.wsdl.PortType;
import javax.wsdl.Service;
import javax.wsdl.Types;
import javax.wsdl.WSDLException;
import javax.wsdl.extensions.ExtensibilityElement;
import javax.wsdl.extensions.http.HTTPAddress;
import javax.wsdl.extensions.http.HTTPBinding;
import javax.wsdl.extensions.http.HTTPOperation;
import javax.wsdl.extensions.mime.MIMEContent;
import javax.wsdl.extensions.schema.Schema;
import javax.wsdl.extensions.soap.SOAPAddress;
import javax.wsdl.extensions.soap.SOAPBinding;
import javax.wsdl.extensions.soap.SOAPBody;
import javax.wsdl.extensions.soap.SOAPFault;
import javax.wsdl.extensions.soap.SOAPOperation;
import javax.wsdl.extensions.soap12.SOAP12Address;
import javax.wsdl.extensions.soap12.SOAP12Binding;
import javax.wsdl.extensions.soap12.SOAP12Body;
import javax.wsdl.extensions.soap12.SOAP12Fault;
import javax.wsdl.extensions.soap12.SOAP12Operation;
import javax.wsdl.factory.WSDLFactory;
import javax.wsdl.xml.WSDLReader;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.future.wsdl.data.BaseTypeTable;
import org.future.wsdl.data.WsdlBinding;
import org.future.wsdl.data.WsdlBindingFault;
import org.future.wsdl.data.WsdlBindingOperation;
import org.future.wsdl.data.WsdlDefinitions;
import org.future.wsdl.data.WsdlFault;
import org.future.wsdl.data.WsdlMessage;
import org.future.wsdl.data.WsdlOperation;
import org.future.wsdl.data.WsdlPort;
import org.future.wsdl.data.WsdlPortType;
import org.future.wsdl.data.WsdlService;
import org.future.wsdl.data.WsdlTypes;
import org.future.wsdl.data.XComplexType;
import org.future.wsdl.data.XElement;
import org.future.wsdl.data.XElementInner;
import org.future.wsdl.data.XSchema;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * 解析 wsdl 文件
 * 一个 wsdl 文件一般分为以下几个部分的内容：<br/>
 * wsdl:definitions <br/>
 * wsdl:types <br/>
 * wsdl:messages <br/>
 * wsdl:portType <br/>
 * wsdl:binding <br/>
 * wsdl:service <br/>
 * 
 * @author dycc
 *
 */
public class WsdlParser {
    
    private Map<String,String> map_namespace = new HashMap<String,String>();
    private static WsdlParser instance;
    
    public static WsdlParser getInstance(){
        if(instance == null){
            instance = new WsdlParser();
        }
        return instance;
    }
    /**
     * 解析 wsdl 文件：数据来自文件 或者 网络
     * @param wsdlURI 指向 wsdl 文件的位置 (can be a filename or URL) 
     * @return
     */
    public WsdlDefinitions load(String wsdlURI)throws WSDLException{
        Definition definition = null;
        WSDLFactory fac = WSDLFactory.newInstance();
        WSDLReader reader = fac.newWSDLReader();
        definition = reader.readWSDL(wsdlURI);
       return analyzeDefinition(definition);
    }   
    /**
     * 解析 wsdl 文件：数据来自指定的string
     * @param byteArray
     * @return
     */
    public WsdlDefinitions loadFromString(byte[] byteArray)throws Exception{
        ByteArrayInputStream in = new ByteArrayInputStream(byteArray);
        return loadFromStream(in);
    }
    /**
     * 解析 wsdl 文件：数据来自 inputStream
     * @param in
     * @return
     */
    public WsdlDefinitions loadFromStream(InputStream in)throws Exception{        
        // get document
        DocumentBuilderFactory docBF = DocumentBuilderFactory.newInstance();
        docBF.setNamespaceAware(true);
        DocumentBuilder docBuilder = docBF.newDocumentBuilder();
        Document doc = docBuilder.parse(in);
        // get definition
        WSDLFactory fac = WSDLFactory.newInstance();
        WSDLReader reader = fac.newWSDLReader();
        Definition definition = reader.readWSDL(null, doc);
        // analyze definition
        return analyzeDefinition(definition);
    }
    /**
     * 分析 Definition
     * @param definition
     * @return
     */
    @SuppressWarnings(value="unchecked")
    public WsdlDefinitions analyzeDefinition(Definition definition){
        WsdlDefinitions wsdl_defi = new WsdlDefinitions();
        // 分析 definition
        if(definition == null){
            return wsdl_defi;
        }
        // store to class field
        map_namespace = definition.getNamespaces();
        // set namespace
        wsdl_defi.setNamespaces(definition.getNamespaces());
        wsdl_defi.setTargetNamespace(definition.getTargetNamespace());
        Element ele = definition.getDocumentationElement();
        if(ele != null){
            wsdl_defi.setDocumentation(ele.getTextContent());
        }
        // Get all the services defined in this Definition.
        Map<QName,Service> map_service = definition.getServices();
        analyzeService(wsdl_defi, map_service);
        // Get all the bindings defined in this Definition.
        Map<QName,Binding> map_binding = definition.getBindings();
        analyzeBinding(wsdl_defi, map_binding);
        // Get all the portTypes defined in this Definition.
        Map<QName,PortType> map_portType = definition.getPortTypes();
        analyzePortType(wsdl_defi,map_portType);
        // Get all the messages defined here.
        Map<QName,Message> map_msg = definition.getMessages();
        analyzeMessage(wsdl_defi,map_msg);
        // Get types defined here.
        Types types = definition.getTypes();
        analyzeTypes(wsdl_defi,types);
        // init relationship
        wsdl_defi.initRelationship();
        // return wsdl_definition
        return wsdl_defi;
    }
    /**
     * 分析 wsdl:service
     * @param wsdl_defi
     * @param map_service
     */
    @SuppressWarnings(value="unchecked")
    private void analyzeService(WsdlDefinitions wsdl_defi,
            Map<QName,Service> map_service){
        Iterator<Service> it = map_service.values().iterator();
        List<WsdlService> services = new ArrayList<WsdlService>();
        while(it.hasNext()){
            Service service = it.next();
            WsdlService wsdl_serv = new WsdlService();
            wsdl_serv.setName(service.getQName().getLocalPart());
            wsdl_serv.setNamespace(map_namespace.get("ns"));
            wsdl_serv.setTargetNamespace(service.getQName().getNamespaceURI());
            // analyze port
            Map<String,Port> map_port = service.getPorts();
            analyzePort(wsdl_serv, map_port);
            // add service
            services.add(wsdl_serv);
        }
        // add wsdl:services
        wsdl_defi.setServices(services);
    }
    /**
     * 分析 wsdl:port
     * @param wsdl_serv
     * @param map_port
     */
    @SuppressWarnings(value="unchecked")
    private void analyzePort(WsdlService wsdl_serv,
            Map<String,Port> map_port){
        Iterator<Port> it_port = map_port.values().iterator();
        List<WsdlPort> ports = new ArrayList<WsdlPort>();
        while(it_port.hasNext()){
            Port port = it_port.next();
            WsdlPort wsdl_port = new WsdlPort();
            wsdl_port.setName(port.getName());
            // 此处由于 port.getBinding().getQName().getPrefix()为 ""
            // 与实际情况不符 故作以下修正
            String nsuri = port.getBinding().getQName().getNamespaceURI();
            String localPart = port.getBinding().getQName().getLocalPart();
            String prefix = queryPrefix(nsuri);
            // setBinding QName
            wsdl_port.setBinding(new QName(nsuri,localPart,prefix));
            // analyze <soap:address .../> element
            List<ExtensibilityElement> extElements = port.getExtensibilityElements();
            for(int i=0;i<extElements.size();i++){
                ExtensibilityElement extEle = extElements.get(i);
                // 此处由于 extEle.getElementType().getPrefix()为 ""
                // 与实际情况不符 故作以下修正
                nsuri = extEle.getElementType().getNamespaceURI();
                localPart = extEle.getElementType().getLocalPart();
                prefix = queryPrefix(nsuri);
                // set <soap:address .../> element QName
                wsdl_port.setAddr_type(new QName(nsuri,localPart,prefix));
                if(extEle instanceof SOAPAddress){
                    wsdl_port.setAddress(((SOAPAddress)extEle).getLocationURI());
                } else if(extEle instanceof SOAP12Address){
                    wsdl_port.setAddress(((SOAP12Address)extEle).getLocationURI());
                } else if(extEle instanceof HTTPAddress){
                    wsdl_port.setAddress(((HTTPAddress)extEle).getLocationURI());
                }
            }// end for
            wsdl_port.setWsdlService(wsdl_serv);
            ports.add(wsdl_port);
        }// end while
        wsdl_serv.setPorts(ports);
    }
    /**
     * 分析：wsdl:binding
     * @param wsdl_defi
     * @param map_binding
     */
    @SuppressWarnings(value="unchecked")
    private void analyzeBinding(WsdlDefinitions wsdl_defi,
            Map<QName,Binding> map_binding){
         Iterator<Binding> it_binding = map_binding.values().iterator();
         List<WsdlBinding> bindings = new ArrayList<WsdlBinding>();
         while(it_binding.hasNext()){
             Binding binding = it_binding.next();
             WsdlBinding wsdl_bind = new WsdlBinding();
             wsdl_bind.setName(binding.getQName().getLocalPart());
             // 此处由于 binding.getPortType().getQName().getPrefix()为 ""
             // 与实际情况不符 故作以下修正
             String nsuri = binding.getPortType().getQName().getNamespaceURI();
             String localPart = binding.getPortType().getQName().getLocalPart();
             String prefix = queryPrefix(nsuri);
             // set <wsdl:binding type="..." .../> element's type attribute QName
             wsdl_bind.setType(new QName(nsuri,localPart,prefix));
             // analyze <soap:binding .../> element
             List<ExtensibilityElement> extElements = binding.getExtensibilityElements();
             for(int i=0;i<extElements.size();i++){
                 ExtensibilityElement extEle = extElements.get(i);
                 // 此处由于 extEle.getElementType().getPrefix()为 ""
                 // 与实际情况不符 故作以下修正
                 nsuri = extEle.getElementType().getNamespaceURI();
                 localPart = extEle.getElementType().getLocalPart();
                 prefix = queryPrefix(nsuri);
                 // set <soap:binding .../> element QName
                 wsdl_bind.setExtType(new QName(nsuri,localPart,prefix));
                 if(extEle instanceof SOAPBinding){
                     wsdl_bind.setTransport(((SOAPBinding)extEle).getTransportURI());
                     wsdl_bind.setStyle(((SOAPBinding)extEle).getStyle());
                 } else if(extEle instanceof SOAP12Binding){
                     wsdl_bind.setTransport(((SOAP12Binding)extEle).getTransportURI());
                     wsdl_bind.setStyle(((SOAP12Binding)extEle).getStyle());
                 } else if(extEle instanceof HTTPBinding){
                     wsdl_bind.setVerb(((HTTPBinding)extEle).getVerb());
                 }
             }// end for
             // wsdl:binding -> wsdl:operation
             List<BindingOperation> bindingOpers = binding.getBindingOperations();
             List<WsdlBindingOperation> wsdl_bind_opers = new ArrayList<WsdlBindingOperation>();
             for(int i=0;i<bindingOpers.size();i++){
                BindingOperation bind_oper = bindingOpers.get(i);
                WsdlBindingOperation wsdl_bind_oper = new WsdlBindingOperation();
                wsdl_bind_oper.setName(bind_oper.getName());
                // analyze <soap:operation .../> element
                extElements = bind_oper.getExtensibilityElements();
                for(int j=0;j<extElements.size();j++){
                    ExtensibilityElement extEle = extElements.get(j);
                    // 此处由于 extEle.getElementType().getPrefix()为 ""
                    // 与实际情况不符 故作以下修正
                    nsuri = extEle.getElementType().getNamespaceURI();
                    localPart = extEle.getElementType().getLocalPart();
                    prefix = queryPrefix(nsuri);
                    // set <soap:operation .../> element QName
                    wsdl_bind_oper.setExtType(new QName(nsuri,localPart,prefix));
                    if(extEle instanceof SOAPOperation){
                        wsdl_bind_oper.setSoapAction(((SOAPOperation)extEle).getSoapActionURI());
                        wsdl_bind_oper.setStyle(((SOAPOperation)extEle).getStyle());
                    } else if(extEle instanceof SOAP12Operation){
                        wsdl_bind_oper.setSoapAction(((SOAP12Operation)extEle).getSoapActionURI());
                        wsdl_bind_oper.setStyle(((SOAP12Operation)extEle).getStyle());
                    } else if(extEle instanceof HTTPOperation){
                        wsdl_bind_oper.setLocation(((HTTPOperation)extEle).getLocationURI());
                    }
                }// end for operation extensibilityElement
                // analyze <wsdl:input>...</wsdl:input> element
                BindingInput input = bind_oper.getBindingInput();
                if(input != null){
                    // analyze <soap:body .../> element
                    extElements = input.getExtensibilityElements();
                    for(int j=0;j<extElements.size();j++){
                        ExtensibilityElement extEle = extElements.get(j);
                        // 此处由于 extEle.getElementType().getPrefix()为 ""
                        // 与实际情况不符 故作以下修正
                        nsuri = extEle.getElementType().getNamespaceURI();
                        localPart = extEle.getElementType().getLocalPart();
                        prefix = queryPrefix(nsuri);
                        // set <soap:body .../> element QName
                        wsdl_bind_oper.setInputExtName(new QName(nsuri,localPart,prefix));
                        if(extEle instanceof SOAPBody){
                            wsdl_bind_oper.setInputUse(((SOAPBody)extEle).getUse());
                        } else if(extEle instanceof SOAP12Body){
                            wsdl_bind_oper.setInputUse(((SOAP12Body)extEle).getUse());
                        } else if(extEle instanceof MIMEContent){
                            wsdl_bind_oper.setInputType(((MIMEContent)extEle).getType());
                            wsdl_bind_oper.setInputPart(((MIMEContent)extEle).getPart());
                        }
                    }// end for extensibilityElement
                }// end if input
                // analyze <wsdl:output>...</wsdl:output> element
                BindingOutput output = bind_oper.getBindingOutput();
                if(output != null){
                    // analyze <soap:body .../> element
                    extElements = output.getExtensibilityElements();
                    for(int j=0;j<extElements.size();j++){
                        ExtensibilityElement extEle = extElements.get(j);
                        // 此处由于 extEle.getElementType().getPrefix()为 ""
                        // 与实际情况不符 故作以下修正
                        nsuri = extEle.getElementType().getNamespaceURI();
                        localPart = extEle.getElementType().getLocalPart();
                        prefix = queryPrefix(nsuri);
                        // set <soap:body .../> element QName
                        wsdl_bind_oper.setOutputExtName(new QName(nsuri,localPart,prefix));
                        if(extEle instanceof SOAPBody){
                            wsdl_bind_oper.setOutputUse(((SOAPBody)extEle).getUse());
                        } else if(extEle instanceof SOAP12Body){
                            wsdl_bind_oper.setOutputUse(((SOAP12Body)extEle).getUse());
                        } else if(extEle instanceof MIMEContent){
                            wsdl_bind_oper.setOutputType(((MIMEContent)extEle).getType());
                            wsdl_bind_oper.setOutputPart(((MIMEContent)extEle).getPart());
                        }
                    }// end for extensibilityElement
                }// end if output
                Map<String,BindingFault> map_fault = bind_oper.getBindingFaults();
                // analyze <wsdl:fault .../>
                analyzeBindingFault(wsdl_bind_oper, map_fault);
                // add wsdl_bind_oper
                wsdl_bind_opers.add(wsdl_bind_oper);
             }
             wsdl_bind.setBindingOperations(wsdl_bind_opers);
             // add wsdl_bind
             bindings.add(wsdl_bind);
         }// end while
         wsdl_defi.setBindings(bindings);
    }
    /**
     * 分析：wsdl:fault
     * @param wsdl_bind_oper
     * @param map_fault
     */
    @SuppressWarnings(value={ "unchecked"})
    private void analyzeBindingFault(WsdlBindingOperation wsdl_bind_oper,
            Map<String,BindingFault> map_fault){
        Iterator<BindingFault> it_fault = map_fault.values().iterator();
        List<WsdlBindingFault> wsdl_faults = new ArrayList<WsdlBindingFault>();
        while(it_fault.hasNext()){
            BindingFault fault = it_fault.next();
            WsdlBindingFault wsdl_fault = new WsdlBindingFault();
            wsdl_fault.setName(fault.getName());
            String nsuri = "", localPart = "", prefix = "";
            // analyze <soap:fault .../> element
            List<ExtensibilityElement> extElements = fault.getExtensibilityElements();
            for(int i=0;i<extElements.size();i++){
                ExtensibilityElement extEle = extElements.get(i);
                // 此处由于 extEle.getElementType().getPrefix()为 ""
                // 与实际情况不符 故作以下修正
                nsuri = extEle.getElementType().getNamespaceURI();
                localPart = extEle.getElementType().getLocalPart();
                prefix = queryPrefix(nsuri);
                // set <soap:binding .../> element QName
                wsdl_fault.setExtQName(new QName(nsuri,localPart,prefix));
                if(extEle instanceof SOAPFault){
                    wsdl_fault.setExtAttrUse(((SOAPFault)extEle).getUse());
                    wsdl_fault.setExtAttrName(((SOAPFault)extEle).getName());
                } else if(extEle instanceof SOAP12Fault){
                    wsdl_fault.setExtAttrUse(((SOAP12Fault)extEle).getUse());
                    wsdl_fault.setExtAttrName(((SOAP12Fault)extEle).getName());
                } 
            }// end for
            wsdl_faults.add(wsdl_fault);
        }
        wsdl_bind_oper.setBindingFaults(wsdl_faults);
    }
    /**
     * 分析：wsdl:portType
     * @param wsdl_defi
     * @param map_portType
     */
    @SuppressWarnings(value={"unchecked"})
    private void analyzePortType(WsdlDefinitions wsdl_defi,
            Map<QName,PortType> map_portType){
        Iterator<PortType> it_portType = map_portType.values().iterator();
        List<WsdlPortType> wsdl_portTypes = new ArrayList<WsdlPortType>();
        while(it_portType.hasNext()){
            PortType portType = it_portType.next();
            WsdlPortType wsdl_portType = new WsdlPortType();
            wsdl_portType.setName(portType.getQName().getLocalPart());
            // get operations
            List<Operation> list_oper = portType.getOperations();
            analyzeOperation(wsdl_portType, list_oper);
            // add wsdl_portType
            wsdl_portTypes.add(wsdl_portType);
        }
        wsdl_defi.setPortTypes(wsdl_portTypes);
    }
    /**
     * 分析：wsdl:operation
     * @param wsdl_portType
     * @param list_oper
     */
    @SuppressWarnings(value={"unchecked"})
    private void analyzeOperation(WsdlPortType wsdl_portType,
            List<Operation> list_oper){
        List<WsdlOperation> list_wsdl_oper = new ArrayList<WsdlOperation>();
        String nsuri = "", localPart = "", prefix = "";
        for(int i=0;i<list_oper.size();i++){
            Operation oper = list_oper.get(i);
            WsdlOperation wsdl_oper = new WsdlOperation();
            wsdl_oper.setName(oper.getName());
            // wsdl:input
            Input input = oper.getInput();
            if(input != null){
                String name = input.getName();
                wsdl_oper.setInName(name);
                nsuri = input.getMessage().getQName().getNamespaceURI();
                localPart = input.getMessage().getQName().getLocalPart();
                prefix = queryPrefix(nsuri);
                wsdl_oper.setInMsgQName(new QName(nsuri,localPart,prefix));
                // analyze wsdl:input extension attribute
                Map<QName,Object> map_extAttr = input.getExtensionAttributes();
                Iterator<QName> it_extAttr = map_extAttr.keySet().iterator();
                while(it_extAttr.hasNext()){
                    QName key = it_extAttr.next();
                    QName val = (QName)map_extAttr.get(key);
                    nsuri = key.getNamespaceURI();
                    localPart = key.getLocalPart();
                    prefix = queryPrefix(nsuri);
                    wsdl_oper.setInActionQName(new QName(nsuri,localPart,prefix));
                    wsdl_oper.setInActionVal(val.getLocalPart());
                }
            }            
            // wsdl:output
            Output output = oper.getOutput();
            if(output != null){
                String name = output.getName();
                wsdl_oper.setOutName(name);
                nsuri = output.getMessage().getQName().getNamespaceURI();
                localPart = output.getMessage().getQName().getLocalPart();
                prefix = queryPrefix(nsuri);
                wsdl_oper.setOutMsgQName(new QName(nsuri,localPart,prefix));
                // analyze wsdl:output extension attribute
                Map<QName,Object> map_extAttr = output.getExtensionAttributes();
                Iterator<QName> it_extAttr = map_extAttr.keySet().iterator();
                while(it_extAttr.hasNext()){
                    QName key = it_extAttr.next();
                    QName val = (QName)map_extAttr.get(key);
                    nsuri = key.getNamespaceURI();
                    localPart = key.getLocalPart();
                    prefix = queryPrefix(nsuri);
                    wsdl_oper.setOutActionQName(new QName(nsuri,localPart,prefix));
                    wsdl_oper.setOutActionVal(val.getLocalPart());
                }
            }
            // wsdl:fault
            Map<String,Fault> map_fault = oper.getFaults();
            analyzeOperationFault(wsdl_oper, map_fault);
            // add wsdl_oper
            wsdl_oper.setWsdlPortType(wsdl_portType);
            list_wsdl_oper.add(wsdl_oper);
        }
        wsdl_portType.setOperations(list_wsdl_oper);
    }
    /**
     * 分析：wsdl:operation
     * @param wsdl_oper
     * @param map_fault
     */
    @SuppressWarnings(value={"unchecked"})
    private void analyzeOperationFault(WsdlOperation wsdl_oper,
            Map<String,Fault> map_fault){
        Iterator<Fault> it_fault = map_fault.values().iterator();
        List<WsdlFault> list_faults = new ArrayList<WsdlFault>();
        String nsuri = "", localPart = "", prefix = "";
        while(it_fault.hasNext()){
            Fault fault = it_fault.next();
            WsdlFault wsdl_fault = new WsdlFault();
            // set name
            wsdl_fault.setName(fault.getName());
            nsuri = fault.getMessage().getQName().getNamespaceURI();
            localPart = fault.getMessage().getQName().getLocalPart();
            prefix = queryPrefix(nsuri);
            // set message QName
            wsdl_fault.setMsgQName(new QName(nsuri,localPart,prefix));
            // analyze wsdl:fault extension attribute
            Map<QName,Object> map_extAttr = fault.getExtensionAttributes();
            Iterator<QName> it_extAttr = map_extAttr.keySet().iterator();
            while(it_extAttr.hasNext()){
                QName key = it_extAttr.next();
                QName val = (QName)map_extAttr.get(key);
                nsuri = key.getNamespaceURI();
                localPart = key.getLocalPart();
                prefix = queryPrefix(nsuri);
                wsdl_fault.setActionQName(new QName(nsuri,localPart,prefix));
                wsdl_fault.setActionVal(val.getLocalPart());
            }
            // add wsdl_fault
            list_faults.add(wsdl_fault);
        }
        wsdl_oper.setFaults(list_faults);
        
    }
    /**
     * 分析：wsdl:message
     * @param wsdl_defi
     * @param map_msg
     */
    @SuppressWarnings(value={"unchecked"})
    private void analyzeMessage(WsdlDefinitions wsdl_defi,
            Map<QName,Message> map_msg){
        Iterator<Message> it_msg = map_msg.values().iterator();
        List<WsdlMessage> list_msgs = new ArrayList<WsdlMessage>();
        String nsuri = "", localPart = "", prefix = "";
        while(it_msg.hasNext()){
            Message msg = it_msg.next();
            WsdlMessage wsdl_msg = new WsdlMessage();
            wsdl_msg.setName(msg.getQName().getLocalPart());
            Map<String,Part> map_part = msg.getParts();
            Iterator<Part> it_part = map_part.values().iterator();
            while(it_part.hasNext()){
                Part part = it_part.next();
                if(part.getElementName() == null){
                    // part 中可以有 name,element 或 name,type 属性组合
                    String name = part.getName();
                    String type = part.getTypeName().getLocalPart();
                    XElementInner innerEle = new XElementInner();
                    innerEle.setName(name);
                    innerEle.setType(type);
                    wsdl_msg.getInnerEleList().add(innerEle);
                    // 此处会覆盖之前的 name
                    wsdl_msg.setPartName(name);
                    continue;
                }
                wsdl_msg.setPartName(part.getName());
                nsuri = part.getElementName().getNamespaceURI();
                localPart = part.getElementName().getLocalPart();
                prefix = queryPrefix(nsuri);
                if(BaseTypeTable.isSimpleXmlType(localPart)){
                    XElementInner innerEle = new XElementInner();
                    innerEle.setName(part.getName());
                    innerEle.setType(localPart);
                    wsdl_msg.getInnerEleList().add(innerEle);
                    continue;
                }
                wsdl_msg.setPartEleQName(new QName(nsuri,localPart,prefix));
            }
            list_msgs.add(wsdl_msg);
        }
        wsdl_defi.setMessages(list_msgs);
    }
    /**
     * 
     * @param wsdl_defi
     * @param types
     */
    @SuppressWarnings(value={"unchecked"})
    private void analyzeTypes(WsdlDefinitions wsdl_defi,
            Types types){
        List<ExtensibilityElement> extElements = types.getExtensibilityElements();
        WsdlTypes wsdl_types = new WsdlTypes();
        List<XSchema> list_schema = new ArrayList<XSchema>();
        for(int i=0;i<extElements.size();i++){
            ExtensibilityElement extEle = extElements.get(i);
            if(!(extEle instanceof Schema)){
                continue;
            }
            Schema schema = (Schema)extEle;
            XSchema xschema = new XSchema();
            Element element = schema.getElement();
            // set tagName
            xschema.setTagName(element.getTagName());
            // xschema attrs
            Map<String,String> map_attr = new HashMap<String,String>();
            NamedNodeMap node_map = element.getAttributes();
            for(int idx = 0;idx<node_map.getLength();idx++){
                Node node = node_map.item(idx);
                map_attr.put(node.getNodeName(), node.getNodeValue());
            }
            // set attribute map
            xschema.setMap_attr(map_attr);
            // xs:import
            List<String> importNsList = new ArrayList<String>();
            Map<String,List> imports = schema.getImports();
            Iterator<String> it_import = imports.keySet().iterator();
            while(it_import.hasNext()){
                String namespaceUri = it_import.next();
                importNsList.add(namespaceUri);
            }
            // set import list
            xschema.setImportNsList(importNsList);
            // xs:complexType or xs:element
            NodeList node_list = element.getChildNodes();
            for(int idx=0;idx<node_list.getLength();idx++){
                Node node = node_list.item(idx);
                String cur_tagname = node.getNodeName();
                // xs:element or element
                if(cur_tagname.indexOf("element") > -1){
                    analyzeElement(xschema, node);
                    continue;
                }
                if(cur_tagname.indexOf("complexType") > -1){
                    analyzeComplexType(xschema, node);
                    continue;
                }
            }
            list_schema.add(xschema);
        }
        wsdl_types.setSchemas(list_schema);
        wsdl_defi.setTypes(wsdl_types);
    }
    /**
     * 分析：xs:element
     * @param xschema
     * @param node
     */
    private void analyzeElement(XSchema xschema,Node node){
        XElement element = new XElement();
        // transform to Element
        Element cur_ele = (Element)node;
        element.setName(cur_ele.getAttribute("name"));
        element.setNamespace(cur_ele.getNamespaceURI());
        // analyze inner element
        NodeList innerNdList = getElementNodeList(cur_ele);
        List<XElementInner> list_inner_ele = new ArrayList<XElementInner>();
        for(int i=0;i<innerNdList.getLength();i++){
            Node cur_node = innerNdList.item(i);
            NamedNodeMap node_map = cur_node.getAttributes();
            XElementInner inner_ele = new XElementInner();
            Node attr_node = null;
            inner_ele.setName(node_map.getNamedItem("name").getNodeValue());
            attr_node = node_map.getNamedItem("minOccurs");
            if(attr_node != null){
                inner_ele.setMinOccurs(attr_node.getNodeValue());
            }
            attr_node = node_map.getNamedItem("maxOccurs");
            if(attr_node != null){
                inner_ele.setMaxOccurs(attr_node.getNodeValue());
            }
            attr_node = node_map.getNamedItem("nillable");
            if(attr_node != null){
                inner_ele.setNillable(attr_node.getNodeValue());
            }
            inner_ele.setType(node_map.getNamedItem("type").getNodeValue());
            list_inner_ele.add(inner_ele);
        }
        element.setInnerEleList(list_inner_ele);
        xschema.getElementList().add(element);
    }
    /**
     * 分析：xs:complexType
     * @param xschema
     * @param node
     */
    private void analyzeComplexType(XSchema xschema,Node node){
        XComplexType complexType = new XComplexType();
        // transform to Element
        Element cur_ele = (Element)node;
        complexType.setName(cur_ele.getAttribute("name"));
        complexType.setNamespace(cur_ele.getNamespaceURI());
        // analyze inner element
        NodeList innerNdList = getElementNodeList(cur_ele);
        List<XElementInner> list_inner_ele = new ArrayList<XElementInner>();
        for(int i=0;i<innerNdList.getLength();i++){
            Node cur_node = innerNdList.item(i);
            NamedNodeMap node_map = cur_node.getAttributes();
            XElementInner inner_ele = new XElementInner();
            Node attr_node = null;
            inner_ele.setName(node_map.getNamedItem("name").getNodeValue());
            attr_node = node_map.getNamedItem("minOccurs");
            if(attr_node != null){
                inner_ele.setMinOccurs(attr_node.getNodeValue());
            }
            attr_node = node_map.getNamedItem("maxOccurs");
            if(attr_node != null){
                inner_ele.setMaxOccurs(attr_node.getNodeValue());
            }
            attr_node = node_map.getNamedItem("nillable");
            if(attr_node != null){
                inner_ele.setNillable(attr_node.getNodeValue());
            }
            inner_ele.setType(node_map.getNamedItem("type").getNodeValue());
            list_inner_ele.add(inner_ele);
        }
        complexType.setInnerEleList(list_inner_ele);
        xschema.getComplexTypeList().add(complexType);
    }
    /**
     * 返回 element 元素列表
     * @param cur_elem
     * @return
     */
    private NodeList getElementNodeList(Element cur_ele){
        NodeList innerNdList = cur_ele.getElementsByTagNameNS("*", "element");
        return innerNdList;
    }
    /**
     * query prefix by namespaceURI
     * @param namespaceURI
     * @return
     */
    public String queryPrefix(String namespaceURI){
        Iterator<String> it = map_namespace.keySet().iterator();
        while(it.hasNext()){
            String prefix = it.next();
            String val = map_namespace.get(prefix);
            if(val.equals(namespaceURI)){
                return prefix;
            }
        }
        return "";
    }
}
